<?php

namespace App\Http\Controllers\DingMaintainRepair;

use App\Http\Controllers\Controller;
use App\Http\Controllers\DingSendNotifyController;
use App\Models\Dict;
use App\Models\MaintainRepair\MrApply;
use App\Models\MaintainRepair\MrApplyDetail;
use App\Models\MaintainRepair\MrApplyFile;
use App\Models\MaintainRepair\MrApplyMaterial;
use App\Models\Role;
use App\Models\Workflow\Workflow;
use App\Models\Workflow\WorkflowLog;
use App\Models\Workflow\WorkflowNode;
use App\Models\Workflow\WorkflowNodeProgram;
use App\User;
use Illuminate\Database\Eloquent\Builder;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Storage;
use Illuminate\Support\Str;

class MrApplyController extends Controller
{
    public $roleId;
    public $roleName;
    public $userId;
    public $userName;
    public $officeName;

    public function getSeeIds($userId)
    {
        $officeOptions = Dict::getOptionsArrByName('职位');
        if ($userId) {
            $userInfo = User::query()->where('ding_user_id', $userId)->first();
            if ($userInfo) {
                $this->roleId = $roleId = DB::table('sys_roles_users')
                    ->where('user_id', $userInfo['id'])
                    ->pluck('role_id')
                    ->toArray();
                $this->roleName = Role::query()->whereIn('id', $roleId)->pluck('name')->toArray();
                $this->userId = $userInfo['id'];
                $this->userName = $userInfo['name'];
                $this->officeName = $officeOptions[$userInfo['office']];
            }
        }
    }

    /**
     * 获取维修申请单列表数据
     *
     * @param  Request  $request
     *
     * @return mixed
     */
    public function applyList(Request $request)
    {
        $params = $request->all();
        $this->getSeeIds($params['ding_user_id']);
        $user_id = $this->userId;
        $params['user_id'] = $user_id;
        $params['group_id'] = $this->roleId;
        $options = Workflow::getOptionsArrByName('维修申请单');
        $node = collect($options)->whereIn('role_id', $params['group_id'])->first();
        $data = $this->getMrApplyList($params)
            ->orderByDesc('number')
            ->get()
            ->toArray();
        $data = $this->transData($data, $node);

        return response()->formatJson(['mrApplyRecord' => $data]);
    }

    /**
     * 维修申请单数据
     *
     * @param $params
     *
     * @return Builder
     */
    public function getMrApplyList($params): Builder
    {
        $options = Workflow::getOptionsArrByName('维修申请单');
        $node = collect($options)->whereIn('role_id', $params['group_id'])->first();
        if ($params['list_status'] == 2) {//已办
            $query = MrApply::with('applyFile')
                ->with([
                    'process' => function ($query) {
                        $query->where('apply_key', 'akbus_mr_apply');
                    }, 'process.node',
                ])
                ->with('logs.node')
                ->whereHas('logs', function ($query) use ($node) {
                    if ($node) {
                        $query->where('node_id', $node['id'])->where('apply_key', 'akbus_mr_apply');
                    }
                });
        } elseif ($params['list_status'] == 1) {//待办
            $query = MrApply::with('applyFile')
                ->with([
                    'process' => function ($query) {
                        $query->where('apply_key', 'akbus_mr_apply');
                    }, 'process.node',
                ])
                ->whereHas('process', function ($query) use ($node) {
                    if ($node) {
                        $status = $node['node_key'] === 'wr_apply_repairer' ? 1 : 2;
                        $query->where('node_id', $node['id'])
                            ->where('status', $status);
                    }
                });
        } else {
            $query = MrApply::with('applyFile')
                ->with([
                    'process' => function ($query) {
                        $query->where('apply_key', 'akbus_mr_apply');
                    }, 'process.node',
                ])
                ->whereHas('process', function ($query) use ($params) {
                    if (isset($params['status']) && $params['status'] !== -1) {
                        $query->where('status', $params['status']);
                    }
                });
            if (isset($params['user_id'])) {
                $query->where('user_id', $params['user_id']);
            }
        }

//         if (($node['node_key'] === 'wr_apply_driver' || $node['node_key'] === 'wr_apply_driver_leader') && isset($params['user_id'])) {
//             $query->where('user_id', $params['user_id']);
//         }

        // 维修厂只能查看自己待维修的单子
        if (isset($node['node_key']) && $node['node_key'] === 'wr_apply_repairer') {
            $query->where('repairer', $this->officeName);
        }

        // 单号
        if (isset($params['number'])) {
            $query->where('number', 'like', '%'.$params['number'].'%');
        }

        // 车牌号
        if (isset($params['license_plate_num'])) {
            $query->where('license_plate_num', 'like', '%'.$params['license_plate_num'].'%');
        }

        // 日期范围
        if (isset($params['date'])) {
            $date = date('Y-m-d', strtotime($params['date']));
            $query->where('date', $date);
        }

        // 分页
        if (isset($params['pageNumber'], $params['pageSize'])) {
            $query
                ->limit($params['pageSize'])
                ->offset(($params['pageNumber'] - 1) * $params['pageSize']);
        }

        return $query;
    }


    /**
     * 数据转换
     *
     * @param  array  $data
     *
     * @return mixed
     */
    public function transData($data, $node)
    {
        $users = User::query()->pluck('name', 'id')->all();
        $state = Dict::getOptionsArrByName('申请单状态');

        foreach ($data as $key => &$apply) {
            // 用户id转化为用户姓名
            if (isset($apply['user_id'])) {
                $data[$key]['user_name'] = $users[$apply['user_id']];
            }
            // 拼接审核状态，如：节点状态（操作人）
            if (isset($apply['process'])) {
                $status = $apply['process']['status'];
                $data[$key]['status'] = $status;
                $data[$key]['reason'] = $apply['process']['reason'];
                $nodeName = $apply['process']['node']['node_name'] ?? '-';
                $data[$key]['current_node'] = $nodeName;
                $data[$key]['current_status'] = $state[$status];
            }
            if (isset($apply['logs'])) {
                $apply['logs'] = $this->rebuildKeys(collect($apply['logs'])->where('node_id', $node['id'])->toArray());
                foreach ($apply['logs'] as $log) {
                    $data[$key]['auditRecord'][] = [
                        'nodeName'   => $log['node']['node_name'],
                        'resultName' => $log['result_name'],
                        'created_at' => $log['created_at'],
                        'reason'     => $log['reason'],
                        'signature'  => $log['signature'],
                        'number'     => $apply['number'],
                    ];
                }
            }
            if (isset($apply['apply_file'])) {
                $files = collect($apply['apply_file'])->groupBy('type')->toArray();
                $data[$key]['apply_file'] = [];
                $data[$key]['apply_file']['driver'] = $files['driver'] ?? [];
                $data[$key]['apply_file']['houqin'] = $files['houqin'] ?? [];
                $data[$key]['apply_file']['weixiu'] = $files['weixiu'] ?? [];
            }
        }

        return $data;
    }

    /**
     * 创建维修申请
     *
     * @param  Request  $request
     *
     * @return mixed
     */
    public function storeApply(Request $request)
    {
        $params = $request->all();
        $this->getSeeIds($params['ding_user_id']);
        $options = Workflow::getOptionsArrByName('维修申请单');
        $node = collect($options)->whereIn('role_id', $this->roleId)->first();
        $params['nodeKey'] = $node['node_key'];
        $params['user_id'] = $this->userId;

        if ($params['license_plate_num']) {
            // 删除陕G
            $params['license_plate_num'] = Str::of($params['license_plate_num'])->replace('陕G', '');
        }
        // UTC时间格式转换为yyyy-mm-dd
        $params['date'] = date('Y-m-d', strtotime($params['date']));
        // 编制单号
        $params['number'] = $this->setApplyNumber($params['date']);
        // 写入主表
        $mrApply = new MrApply($params);
        $result = $mrApply->save();

        $message = $result ? '添加成功' : '添加失败';

        // 关联司机上传图片
        if (! empty($params['driverUploadFile'])) {
            foreach ($params['driverUploadFile'] as $file) {
                $file['type'] = 'driver';
                $mrApplyFile = new MrApplyFile($file);
                $mrApply->applyFile()->save($mrApplyFile);
            }
        }
        $params['sign'] = isset($params['sign']) ? $params['sign'] : null;

        $this->updateWorkflow($mrApply, $params['nodeKey'], $params['nodeType'], '', null, $params['sign']);

        return response()->formatJson($result, $message);
    }

    /**
     * 设置申请单号
     * 单号规则：yyyymmdd+xxx(编号)，每天编号从001开始，且唯一
     * 如：20200101001
     *
     * @param $date
     *
     * @return string
     */
    public function setApplyNumber($date)
    {
        $applyCount = MrApply::withTrashed()->where('date', 'like', $date.'%')->count();

        return date('Ymd', strtotime($date)).sprintf('%03d', $applyCount + 1);
    }

    /**
     * 更新工作流状态，写入审核状态日志
     *
     * @param $modelObj
     * @param $nodeKey
     * @param $nodeType
     * @param $reason
     * @param $condition
     * @param  null  $sign
     */
    public function updateWorkflow($modelObj, $nodeKey, $nodeType, $reason, $condition, $sign = null)
    {
        // 获取数据表名称
        $tableName = $modelObj->getTableName();

        // 1、查询节点
        $node = WorkflowNode::query()->firstWhere('node_key', $nodeKey);

        // 2、查询是否有维修厂数据
        $mrApply = $modelObj->load('material', 'detail')->toArray();
        $isWxCheck = ($mrApply['material'] || $mrApply['detail']) && $nodeKey !== 'wr_apply_repairer' ? 1 : 0;

        // 3、根据节点ID和节点类型，查询节点流转状态
        $nodeProgramQuery = WorkflowNodeProgram::query()
            ->where('node_id', $node->id)
            ->where('result_key', $nodeType)
            ->where('is_wx_check', $isWxCheck);

        if ($isWxCheck === 0) {
            $nodeProgramQuery->where('condition', $condition);
        }
        $nodeProgram = $nodeProgramQuery->first();

        // 4、保存当前流程状态
        $workflowProcessData = [
            'apply_key'   => $tableName,
            'node_id'     => $nodeProgram->next_node_id,
            'result_name' => $nodeProgram->result_name,
            'status'      => $nodeProgram->result_status,
            'reason'      => $reason,
        ];
        $modelObj->process()->updateOrCreate(
            [
                'apply_id'  => $modelObj->id,
                'apply_key' => $tableName,
            ],
            $workflowProcessData
        );

        // 5、记录流程日志
        $workflowLogData = [
            'apply_key'   => $tableName,
            'node_id'     => $nodeProgram->node_id,
            'result_name' => $nodeProgram->result_name,
            'status'      => $nodeProgram->result_status,
            'reason'      => $reason,
            'signature'   => $sign,
        ];
        $workflowLog = new WorkflowLog($workflowLogData);
        $modelObj->logs()->save($workflowLog);

        // 发送钉钉消息通知，只有在待办和退回的情况下推送
        if ($nodeProgram->result_status === 2 || $nodeProgram->result_status === 4) {
            $dingPush = new DingSendNotifyController();
            $description = '维修申请-'.$this->userName.'-'.$mrApply['license_plate_num'].PHP_EOL.
                '单号：'.$mrApply['number'].PHP_EOL.
                '时间：'.$mrApply['created_at'];
            $dingPush->userNotify($nodeProgram->next_node_id, '', '', $description);
        }
    }

    /**
     * 创建维修
     *
     * @param  Request  $request
     *
     * @return mixed
     */
    public function storeWeixiu(Request $request)
    {
        $params = $request->all();
        $this->getSeeIds($params['ding_user_id']);
        $options = Workflow::getOptionsArrByName('维修申请单');
        $node = collect($options)->whereIn('role_id', $this->roleId)->first();
        $params['nodeKey'] = $node['node_key'];
        //进出厂时间添加判断
        $params['enter_at'] = $params['enter_at'] ? date('Y-m-d H:i:s', strtotime($params['enter_at'])) : null;
        $params['out_at'] = $params['out_at'] ? date('Y-m-d H:i:s', strtotime($params['out_at'])) : null;

        $id = isset($params['id']) ? $params['id'] : 0;
        $this->getSeeIds($params['ding_user_id']);
        $params['user_id'] = $this->userId;

        $mrApply = MrApply::query()->find($id);
        // 出入场时间
        $mrApply->update(['enter_at' => $params['enter_at'], 'out_at' => $params['out_at'],]);
        // 关联后勤部上传照片
        if (! empty($params['weixiuUploadFile'])) {
            $mrApply->applyFile()->delete();
            foreach ($params['weixiuUploadFile'] as $file) {
                $file['type'] = 'weixiu';
                $mrApplyFile = new MrApplyFile($file);
                $mrApply->applyFile()->save($mrApplyFile);
            }
        }

        // 关联维修费
        if (! empty($params['detail'])) {
            $mrApply->detail()->delete();
            foreach ($params['detail'] as $pay) {
                $detail = new MrApplyDetail($pay);
                $mrApply->detail()->save($detail);
            }
        }

        // 关联材料费
        if (! empty($params['material'])) {
            $mrApply->material()->delete();
            foreach ($params['material'] as $pay) {
                $material = new MrApplyMaterial($pay);
                $mrApply->material()->save($material);
            }
        }

        if ($params['nodeType'] === 'submit') {
            $applyWithLogs = $mrApply->load([
                'logs' => function ($query) {
                    $query->where('apply_key', 'akbus_mr_apply')->orderBy('created_at');
                },
            ])->toArray();
            $nodeKey = WorkflowNode::query()->find($applyWithLogs['logs'][0]['node_id']);

            $this->updateWorkflow($mrApply, $params['nodeKey'], $params['nodeType'], '', $nodeKey->node_key);
        }

        return response()->formatJson(true);
    }

    /**
     * 获取申请单数据到编辑表单页面
     *
     * @param $id
     *
     * @return mixed
     */
    public function editApply(Request $request)
    {
        $params = $request->all();

        $id = isset($params['id']) ? $params['id'] : 0;
        $mrApply = MrApply::with('applyFile')
            ->with([
                'process' => function ($query) {
                    $query->where('apply_key', MrApply::getTableName());
                }, 'process.node',
            ])
            ->with([
                'logs' => function ($query) {
                    $query->where('apply_key', MrApply::getTableName());
                }, 'logs.node',
            ])
            ->with('detail')
            ->with('material')
            ->find($id)
            ->toArray();

        $data = [$mrApply];

        $users = User::query()->pluck('name', 'id')->all();
        $state = Dict::getOptionsArrByName('申请单状态');

        foreach ($data as $key => &$apply) {
            // 用户id转化为用户姓名
            if (isset($apply['user_id'])) {
                $data[$key]['user_name'] = $users[$apply['user_id']];
            }
            // 拼接审核状态，如：节点状态（操作人）
            if (isset($apply['process'])) {
                $status = $apply['process']['status'];
                $data[$key]['status'] = $status;
                $data[$key]['reason'] = $apply['process']['reason'];
                $nodeName = $apply['process']['node']['node_name'] ?? '-';
                $data[$key]['current_node'] = $nodeName;
                $data[$key]['current_status'] = $state[$status];
                // $data[$key]['current_result'] = $state[$status].$nodeName;
            }
            if (isset($apply['logs'])) {
                foreach ($apply['logs'] as $log) {
                    $data[$key]['auditRecord'][] = [
                        'nodeName'   => $log['node']['node_name'],
                        'resultName' => $log['result_name'],
                        'created_at' => $log['created_at'],
                        'reason'     => $log['reason'],
                        'signature'  => $log['signature'],
                        'number'     => $apply['number'],
                    ];
                }
            }
            if (isset($apply['apply_file'])) {
                $files = collect($apply['apply_file'])->groupBy('type')->toArray();
                $data[$key]['apply_file'] = [];
                $data[$key]['apply_file']['driver'] = $files['driver'] ?? [];
                $data[$key]['apply_file']['houqin'] = $files['houqin'] ?? [];
                $data[$key]['apply_file']['weixiu'] = $files['weixiu'] ?? [];
            }
        }

        return response()->formatJson($data[0]);
    }

    /**
     * 修改维修申请
     *
     * @param  Request  $request
     *
     * @return mixed
     */
    public function updateApply(Request $request)
    {
        $params = $request->all();
        $id = isset($params['id']) ? $params['id'] : 0;
        if ($params['license_plate_num']) {
            // 删除陕G
            $params['license_plate_num'] = Str::of($params['license_plate_num'])->replace('陕G', '');
        }
        // 更新主表数据
        $mrApply = MrApply::query()->find($id);
        $result = $mrApply->update($params);

        $message = $result ? '修改成功' : '修改失败';

        // 更新关联文件
        if (! empty($params['driverUploadFile'])) {
            // 1. 删除关联文件
            $mrApply->applyFile()->delete();
            // 2. 重新关联文件
            foreach ($params['driverUploadFile'] as $file) {
                $file['type'] = 'driver';
                $mrApplyFile = new MrApplyFile($file);
                $mrApply->applyFile()->save($mrApplyFile);
            }
        }

        if (isset($params['appraisal'])) {
            $condition = $params['appraisal'] < 5000 ? '<' : '>=';
        } else {
            $condition = null;
        }
        $params['sign'] = isset($params['sign']) ? $params['sign'] : null;
        $this->updateWorkflow($mrApply, $params['nodeKey'], $params['nodeType'], '', $condition, $params['sign']);

        return response()->formatJson($result, $message);
    }

    /**
     * 删除维修申请
     *
     * @param  Request  $request
     *
     * @return mixed
     */
    public function destroyApply(Request $request)
    {
        $result = false;
        if ($request->has('ids')) {
            $ids = explode(',', $request['ids']);
            $mrApplyCount = MrApply::destroy($ids);
            $result = $mrApplyCount !== 0;
        }

        $message = $result ? '删除成功' : '删除失败';

        return response()->formatJson($result, $message);
    }

    /**
     * 审核维修申请
     *
     * @param  Request  $request
     *
     * @return JsonResponse
     */
    public function audit(Request $request)
    {
        $params = $request->all();
        $options = Workflow::getOptionsArrByName('维修申请单');
        $this->getSeeIds($params['ding_user_id']);
        $node = collect($options)->whereIn('role_id', $this->roleId)->first();
        $params['nodeKey'] = $node['node_key'];
        $mrApply = MrApply::query()->find($params['id']);
        if (isset($params['appraisal'])) {
            $mrApply->update($params);
            $condition = $params['appraisal'] < 5000 ? '<' : '>=';
        } else {
            $condition = null;
        }

        // 关联后勤部上传照片
        if (! empty($params['houqinUploadFile'])) {
            foreach ($params['houqinUploadFile'] as $file) {
                $file['type'] = 'houqin';
                $mrApplyFile = new MrApplyFile($file);
                $mrApply->applyFile()->save($mrApplyFile);
            }
        }
        $params['sign'] = isset($params['sign']) ? $params['sign'] : null;
        $params['reason'] = isset($params['reason']) ? $params['reason'] : null;
        $this->updateWorkflow(
            $mrApply, $params['nodeKey'], $params['nodeType'], $params['reason'], $condition, $params['sign']
        );

        $message = $params['nodeType'] === 'pass' || $params['nodeType'] === 'end' ? '审核通过' : '审核不通过';

        return response()->formatJson(['result' => true, 'nodeType' => $params['nodeType']], $message);
    }

    /**
     * 上传文件，并返回文件的一些详细信息
     *
     * @param  Request  $request
     *
     * @return mixed
     */
    public function uploadFile(Request $request)
    {
        $uploadedFile = $request->file('file');

        $saveDir = $request->has('saveDir') ? $request->input('saveDir') : 'upload';
        $fileType = $request->has('type') ? $request->input('type') : 'file';
        $ding_user_id = $request->has('ding_user_id') ? $request->input('ding_user_id') : '';
        $this->getSeeIds($ding_user_id);

        // 文件大小（Kb）
        $fileSize = $uploadedFile->getSize();

        // 扩展名
        $extension = $uploadedFile->getClientOriginalExtension();

        // 文件重命名，确保唯一
        $fileName = time().'-'.$uploadedFile->getClientOriginalName();

        // 获取用户
        $userName = $this->userName;;
        $userId = $this->userId;;

        // 保存文件
        Storage::putFileAs(
            'public/'.$saveDir.'/'.$fileType,
            $uploadedFile,
            $fileName
        );

        // 文件路径
        $path = config('app.url').'/storage/'.$saveDir.'/'.$fileType.'/'.$fileName;

        return response()->formatJson([
            'success' => true,
            'url'     => $path,
            'detail'  => [
                'file_name'  => $fileName,
                'file_path'  => $path,
                'file_size'  => $fileSize,
                'file_type'  => $extension,
                'created_at' => date('Y-m-d H:i:s'),
                'user_name'  => $userName,
                'user_id'    => $userId,
                'note'       => '',
            ],
        ], '上传成功');
    }

    public function rebuildKeys($array)
    {
        if (! is_array($array)) {
            return $array;
        }
        $keys = implode('', array_keys($array));
        if (is_numeric($keys)) {
            $array = array_values($array);
        }
        $array = array_map([$this, 'rebuildKeys'], $array);

        return $array;
    }
}
